#include "app_buffer.h"
#include "log.h"
#include "string.h"
#include "stdlib.h"
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>

/**
 * 初始化缓冲区
 * @param 其中一份缓冲区的大小 实际双缓冲 会占用total_size*2的空间
 *
 *  //1  创建大缓冲区 开辟内存
    //2  创建小缓冲区 开辟内存  创建两个  每个u单独的内存储 空间大小 ，数据a长度给0
    //3   指定哪个为读缓冲区  哪个为写缓冲区
    //4  锁初始化
 */

#define MESSAGE_MAX_SIZE 255

buffer_t *app_buffer_init(int total_size)
{
    // 1  创建大缓冲区 开辟内存
    buffer_t *buffer = (buffer_t *)malloc(sizeof(buffer_t));

    // 2  创建小缓冲区 开辟内存  创建两个  每个u单独的内存储 空间大小 ,数据a长度给0
    for (int i = 0; i < 2; i++)
    {
        sub_buffer_t *sub_buffer = (sub_buffer_t *)malloc(sizeof(sub_buffer_t));
        sub_buffer->ptr = malloc(total_size);
        sub_buffer->total_size = total_size;
        sub_buffer->len = 0;
        buffer->sub_buffers[i] = sub_buffer;
    }

    // 3   指定哪个为读缓冲区  哪个为写缓冲区
    buffer->read_index = 0;
    buffer->write_index = 1;

    // 4  锁初始化
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);

    return buffer;
}

/**
 *  向缓冲区写入
 * @return 0 成功 -1 失败
 *  1  获取写缓冲区
 *  2  校验长度是否足够写入
 *  3  写入数据
 */
int app_buffer_write(buffer_t *buffer, char *write_data, uint8_t write_len)
{

    if (write_len > MESSAGE_MAX_SIZE)
    {
        log_error("待写入长度超过最大长度!:%d", MESSAGE_MAX_SIZE);
        return -1;
    }

    log_info("缓冲区写入开始 加锁!");
    int ret = pthread_mutex_lock(&buffer->swap_lock);
    if (ret < 0)
    {
        perror("缓冲区加锁失败!");
        return -1;
    }

    log_info("缓冲区写入开始!");

    // *  1  获取写缓冲区
    sub_buffer_t *write_sub_buffer = buffer->sub_buffers[buffer->write_index];
    //*  2  校验长度是否足够写入  +1有一个长度字节
    if (write_len + 1 > write_sub_buffer->total_size - write_sub_buffer->len)
    {
        log_error("待写入长度超过剩余写入空间!,释放锁");
        pthread_mutex_unlock(&buffer->swap_lock);
        return -1;
    }
    //*  3  写入数据  + 长度增加
    write_sub_buffer->ptr[write_sub_buffer->len] = (char)write_len;
    memcpy(write_sub_buffer->ptr + write_sub_buffer->len + 1, write_data, write_len);
    write_sub_buffer->len += write_len + 1;
    
    log_info("缓冲区写入完成, 释放锁!");
    pthread_mutex_unlock(&buffer->swap_lock);

    return 0;
}

/**
 *  切换缓冲区
 */
static int app_buffer_swap(buffer_t *buffer)
{
     log_info("切换缓冲区 加锁!");
    int ret = pthread_mutex_lock(&buffer->swap_lock);
    if (ret < 0)
    {
        perror("缓冲区加锁失败!");
        return -1;
    }
    // 读写下标号的交换
    int tmp_index = buffer->read_index;
    buffer->read_index = buffer->write_index;
    buffer->write_index = tmp_index;
    pthread_mutex_unlock(&buffer->swap_lock);
    log_info("切换缓冲区 释放锁!");
    return 0;
}

/**
 *  从缓冲区读取
 *  @param 1 缓冲区 2 写入的目标空间(已分配空间) ,3 目标可用空间
 *  @return 最终实际读取的数据量
 *   1  获取读缓冲区
 *   2  检查在当前读缓冲区可读的长度  如果缓冲区长度等于0 则切换缓冲区
 *   3  获得可读的长度 取帧头的长度
 *   4  进行读取数据  1)读数据到目标空间  2）用后面的数据覆盖掉前面的数据 3  长度减少 
 *   5 只要读缓冲区可读的长度等于0  进行读写缓冲区的切换
 *   6  返回最终实际读取的数据量
 */
int app_buffer_read(buffer_t *buffer, char *read_buff, int read_buff_size)
{ // A  此处加锁 因为下面的操作设计到了 公共数据
    pthread_mutex_lock(&buffer->read_lock);
    // *   1  获取读缓冲区
    sub_buffer_t *read_sub_buffer = buffer->sub_buffers[buffer->read_index];

    // *   2 检查在当前读缓冲区可读的长度  如果缓冲区长度等于0 则切换缓冲区
    if (read_sub_buffer->len == 0)
    {
        log_info("缓冲区为空! 尝试切换缓冲区");
        int ret= app_buffer_swap(buffer);
        if(ret!=0)
        {
            log_error("切换缓冲区失败!");
            return -1;
        }
        read_sub_buffer = buffer->sub_buffers[buffer->read_index];
        if (read_sub_buffer->len == 0)
        {
            log_error("缓冲区为空!");
            return -1;
        }
    }
    // 3 获得可读的长度 取帧头的长度
    uint8_t data_len = read_sub_buffer->ptr[0];
    log_info("帧头中数据长度: %d",data_len);
    if (data_len > read_buff_size)
    {
        log_error("数据长度超过目标可用空间!");
        return -1;
    }

    // *  4 进行读取数据  1)读数据到目标空间  2）用后面的数据覆盖掉前面的数据 3  长度减少

    memcpy(read_buff, read_sub_buffer->ptr + 1, data_len);
    memmove(read_sub_buffer->ptr, read_sub_buffer->ptr + (data_len + 1), read_sub_buffer->len - (data_len + 1));
    read_sub_buffer->len -= (data_len + 1);

    //*    5  只要读缓冲区可读的长度等于0  进行读写缓冲区的切换
    if (read_sub_buffer->len == 0)
    {
        app_buffer_swap(buffer);
    }
    pthread_mutex_unlock(&buffer->read_lock);
    //*   6 返回最终实际读取的数据量
    return data_len;
}

/**
 * i释放缓冲u区
 */
void app_buffer_free(buffer_t *buffer)
{ // 1  释放所有子缓冲区的数据j空间
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);
    // 2  释放所有子缓冲区结构体空间
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);
    // 3  释放主缓冲区结构体空间
    free(buffer);
}